package galaxy.app;

import galaxy.app.common.EntityFeature;
import galaxy.app.common.ScheduleComponent;
import galaxy.app.common.ScheduleSystem;
import galaxy.app.consts.ScheduleType;
import galaxy.app.dispatch.DispatcherComponent;
import galaxy.app.dispatch.DispatcherSystem;
import galaxy.app.event.EventComponent;
import galaxy.app.event.EventSystem;
import galaxy.app.log.LogHelper;
import galaxy.app.network.rpc.client.RpcClientComponent;
import galaxy.app.network.rpc.client.RpcClientSystem;
import galaxy.app.network.rpc.server.NettyRpcServerSystem;
import galaxy.app.network.session.GateSessionServiceComponent;
import galaxy.app.network.session.GateSessionServiceSystem;
import galaxy.app.network.session.NodeSessionComponent;
import galaxy.app.network.session.NodeSessionSystem;
import galaxy.app.network.websocket.WebSocketServerSystem;
import galaxy.app.route.RouteComponent;
import galaxy.app.route.RouteSystem;
import galaxy.app.system.LaunchSys;
import galaxy.app.system.ConfigComponent;
import galaxy.app.system.ConfigSystem;
import galaxy.kernel.ECSAdmin;
import galaxy.kernel.ObjectReference;
import galaxy.kernel.common.ComponentCallback;
import galaxy.kernel.component.ECSComponents;
import galaxy.kernel.entity.ECSEnties;
import galaxy.kernel.entity.ECSEntity;
import galaxy.kernel.entity.Entity;
import galaxy.kernel.system.ECSSystem;
import galaxy.kernel.system.ECSSystems;

public class Galaxy {
    private static ObjectReference<Galaxy> ref = new ObjectReference<>();

    private long startTime = System.currentTimeMillis();

    private ECSAdmin admin = new ECSAdmin();

    public static Galaxy call() {
        return ref.get();
    }

    public static ECSAdmin admin(){
        return call().getAdmin();
    }

    public static ECSEnties entities(){
        return call().getAdmin().entities;
    }

    public static ECSComponents components(){
        return call().getAdmin().components;
    }

    public static ECSSystems systems(){
        return call().getAdmin().systems;
    }

    public static Galaxy createApp(String configPath, String envName, String nodeId) throws Exception {
        Galaxy galaxy = new Galaxy(configPath, "env", envName, nodeId);
        ref.set(galaxy);
        
        galaxy.init(configPath, "env", envName, nodeId);
        return galaxy;
    }

    private void init(String configPath, String string, String envName, String nodeId) {
        // 后续可以用ioc处理

        admin.components.add(new ConfigComponent());
        admin.systems.add(new ConfigSystem(configPath,string,envName,nodeId));

        // event route
        admin.components.add(new EventComponent());
        admin.systems.add(new EventSystem());
        admin.components.add(new RouteComponent());
        admin.systems.add(new RouteSystem());

        // gatesession  nodesession
        admin.components.add(new NodeSessionComponent());
        admin.systems.add(new NodeSessionSystem());
        admin.components.add(new GateSessionServiceComponent());
        admin.systems.add(new GateSessionServiceSystem());

        admin.systems.add(new NettyRpcServerSystem());
        admin.systems.add(new WebSocketServerSystem());
    }

    public Galaxy(String configPath, String string, String envName, String nodeId) {
        

    }

    public ECSAdmin getAdmin(){
        return admin;
    }

    public void start(ComponentCallback... callback){

        // LaunchSys launch = admin.get(LaunchSys.class);
        // launch.start();
        systems().start();

        for (ComponentCallback c : callback) {
            c.execute();
        }

        ConfigComponent config = components().getSingle(ConfigComponent.class);
        LogHelper.info(config.currentNode.toString());
        LogHelper.warn("========== {} launcher complete runTime:{}ms ==========", config.nodeId, System.currentTimeMillis() - this.startTime);
    
    }

    public Galaxy addEntity(Object entity) {
        return this;
    }

    public Galaxy addEntity(EntityFeature<ECSEntity> feature) {
        ECSEntity e = feature.createComponent(this);
        entities().add(e);
        return this;
    }

    // public GateSessionService sessionService() {
    //     return this.sessionService;
    // }

    public NodeSessionSystem nodeSessionSystem() {
        return systems().get(NodeSessionSystem.class);
    }

    public Galaxy addDispatch() {
        RpcClientComponent c = components().getSingle(RpcClientComponent.class);
        if (c == null) {
            components().add(new DispatcherComponent());
            systems().add(new DispatcherSystem());
        }

        return this;
    }

    public Galaxy addRpcClient(String... nodeTypes) {
        RpcClientSystem rpc = systems().get(RpcClientSystem.class);
        if (rpc == null) {
            components().add(new RpcClientComponent());
            rpc = new RpcClientSystem();
            systems().add(rpc);

            rpc.add(nodeTypes);
        }
        return this;
    }

    public ScheduleSystem addSchedule(int threadSize, String name) {
        ScheduleSystem s = systems().get(ScheduleSystem.class);
        if (s == null) {
            components().add(new ScheduleComponent());
            s = new ScheduleSystem();
            systems().add(s);
           
        }
        s.addSchedule(threadSize, name);
        // ScheduleComponent c = components().getSingle(ScheduleComponent.class);
        // Entity e;
        // if (c == null) {
        //      e = new Entity();
        //     entities().add(e);
        // }else{
        //     e = entities().get(c.entityId);
        // }
        // c = new ScheduleComponent();
        // e.addComponent(c);
        
        return s;
    }

    public Galaxy addDefaultSchedule(){
        ScheduleSystem s = systems().get(ScheduleSystem.class);
        if (s == null) {
            s = addSchedule(4,ScheduleType.APP);
        }
        return this;
    }

    public static ScheduleSystem schedule(){
        return call().systems().get(ScheduleSystem.class);
    }
    
}
